////////////////////////////////////////////////////////////////////////////
// Copyright (c) 2012 Kentaro Sekimoto  All rights reserved.
////////////////////////////////////////////////////////////////////////////

#include <tinyhal.h>
#include "..\FM4.h"

void ExInt0_7(void *arg) __attribute__ ((interrupt));
void ExInt8_31(void *arg) __attribute__ ((interrupt));

#if defined(MB9BF568R)
#include "FM4_GPIO_MB9BF568R.h"
#else
#error "CPU type not defined."
#endif

#define MIN_DEBOUNCETIMEMS  1       // 1ms
#define MAX_DEBOUNCETIMEMS  5000    // 5s

UINT8 m_GPIO_Driver_Initialized = FALSE;
UINT8 m_GPIO_Reserved[FM4_GPIO_MAX_PINS];
UINT32 m_DebounceTicks;

#ifdef FM4_GPIO_INT

BOOL m_GPIO_InISR = FALSE;
UINT16 m_GPIO_PortLastValues[FM4_GPIO_MAX_PORTS];
UINT16 m_GPIO_PortReservedMask[FM4_GPIO_MAX_PORTS];
HAL_COMPLETION m_GPIO_Completion;

PIN_ISR_DESCRIPTOR m_PinIsr[MAX_GPIO_INT];
INT8 m_PinIsr_Ptr[FM4_GPIO_MAX_PINS];
INT8 m_PinIsr_Index;

INT8 PinIsr_AvailableIndex(GPIO_PIN pin)
{
    for (INT8 i = 0; i < MAX_GPIO_INT; i++) {
        if (m_PinIsr[i].m_pin == pin) {
            return i;
        }
    }
    for (INT8 i = 0; i < MAX_GPIO_INT; i++) {
        if (m_PinIsr[i].m_pin == PPP)
            return i;
    }
    return -1;
}

#ifdef USE_FM4_GPIO_EXT_INT
BOOL ExIntAvailable(GPIO_PIN pin)
{
    return (c_GPIO_IntNo[(UINT8)pin] != NOINT);
}

void ExIntDisable(GPIO_PIN pin)
{
    UINT32 port = GPIO_PORT(pin);
    UINT32 mask = GPIO_MASK(pin);
    UINT32 intno = c_GPIO_IntNo[pin] & 0x1F;
    GLOBAL_LOCK(irq);
    GPIO_PFR(port) |= mask;             // Changed to Pheripheral
    FM4_EXTI->ENIR &= ~(1 << intno);    // Clear ENable Interrupt request Register
    m_GPIO_IrqToPin[intno] = PPP;
}

void ExIntChangeEdge(GPIO_PIN pin, UINT32 edge)
{
    UINT32 intno = c_GPIO_IntNo[pin] & 0x1F;
    UINT32 intno2 = intno * 2;
    if (intno < 16) {
        FM4_EXTI->ELVR = (FM4_EXTI->ELVR & (0xFC << intno2)) | (edge << intno2);
#ifdef MB9BF618T
    } else {
        intno2 -= 0x20;
        FM4_EXTI->ELVR1 = (FM4_EXTI->ELVR1 & (0xFC << intno2)) | (edge << intno2);
#endif
    }
}

void ExIntEnable(GPIO_PIN pin, UINT32 edge)
{
    UINT32 port = GPIO_PORT(pin);
    UINT32 mask = GPIO_MASK(pin);
    UINT32 intno = c_GPIO_IntNo[pin] & 0x1F;
    UINT32 intno2 = intno * 2;
    UINT32 intmd = c_GPIO_IntNo[pin] >> 5;
    GLOBAL_LOCK(irq);
    m_GPIO_IrqToPin[intno] = pin;
    GPIO_PFR(port) &= ~mask;            // Change to GPIO
    FM4_EXTI->ENIR &= ~(1 << intno);    // Clear ENable Interrupt request Register
    if (intno < 16) {
        FM4_GPIO->EPFR06 |= ((intmd+1) << intno2);
        FM4_EXTI->ELVR = (FM4_EXTI->ELVR & (0xFC << intno2)) | (edge << intno2);
#ifdef MB9BF618T
    } else {
        intno2 -= 0x20;
        FM4_GPIO->EPFR15 |= ((intmd+1) << intno2);
        FM4_EXTI->ELVR1 = (FM4_EXTI->ELVR1 & (0xFC << intno2)) | (edge << intno2);
#endif
    }
    FM4_EXTI->EICL |= ~(1 << intno);    // Clear External Interrupt CLear register
    FM4_EXTI->ENIR |= (1 << intno);     // Set ENable Interrupt request Register
}
#endif

INT32 GetBitPos(UINT32 val, UINT32 size)
{
    INT32 pos = 0;
    while (pos < size) {
        if (val & 1)
            return pos;
        pos++;
        val >>= 1;
    }
    return -1;
}

void UpdatePinValue(GPIO_PIN pin)
{
    UINT32 port = GPIO_PORT(pin);
    UINT32 mask = GPIO_MASK(pin);
    m_GPIO_PortLastValues[port] &= ~mask;
    m_GPIO_PortLastValues[port] |= (GPIO_PDIR(port) & mask);
}

void EnableInputPolling(GPIO_PIN pin)
{
    m_GPIO_PortReservedMask[GPIO_PORT(pin)] |= GPIO_MASK(pin);
}

void DisableInputPolling(GPIO_PIN pin)
{
    m_GPIO_PortReservedMask[GPIO_PORT(pin)] &= ~GPIO_MASK(pin);
}

UINT32 ChkPinChange(void)
{
    INT32 i, pos;
    UINT16 val, b, reserved_mask;
    UINT32 pin = 255;
    GLOBAL_LOCK(irq);
    for (i = 0; i < FM4_GPIO_MAX_PORTS; i++) {
        //reserved_mask = m_GPIO_PortReservedMask[i] & ~GPIO_PFR(i);
        reserved_mask = m_GPIO_PortReservedMask[i];
        if (reserved_mask) {
            val = GPIO_PDIR(i) & reserved_mask;
            if (m_GPIO_PortLastValues[i] != val) {
                b = m_GPIO_PortLastValues[i] ^ val;
                m_GPIO_PortLastValues[i] = val;
                pos = GetBitPos((UINT32)b, 16);
                if (pos != -1) {
                    pin = i*16 + pos;
                    if (pin != 255) {
                        //lcd_printf("%02X ", pin);
                        PIN_ISR_DESCRIPTOR& pinIsr = m_PinIsr[m_PinIsr_Ptr[pin]];
                        if (b & val) {
                            // low -> high
                            pinIsr.m_status = PIN_ISR_DESCRIPTOR::c_Status_AllowHighEdge;
                            //lcd_printf("+");
                        } else {
                            // high -> low
                            pinIsr.m_status = PIN_ISR_DESCRIPTOR::c_Status_AllowLowEdge;
                            //lcd_printf("-");
                        }
                    }
                    break;
                }
            }
        }
    }
    return pin;
}

void PIN_ISR_DESCRIPTOR::Fire(void *arg)
{
    NATIVE_PROFILE_HAL_PROCESSOR_GPIO();
    UINT32 edge;
    PIN_ISR_DESCRIPTOR *desc = (PIN_ISR_DESCRIPTOR *)arg;
    desc->m_isr(desc->m_pin, (desc->m_status & c_Status_AllowHighEdge) != 0, desc->m_param);
    UINT8 mask = c_Flags_RequireHighEdge | c_Flags_RequireLowEdge;
    if ((desc->m_flags & mask) == mask) {
        desc->m_status ^= PIN_ISR_DESCRIPTOR::c_Status_AllowLowEdge | PIN_ISR_DESCRIPTOR::c_Status_AllowHighEdge;
#ifdef USE_FM4_GPIO_EXT_INT
        if (desc->m_status & PIN_ISR_DESCRIPTOR::c_Status_AllowLowEdge)
            edge = FM4_INT_EDGE_LOW;
        else
            edge = FM4_INT_EDGE_HIGH;
        ExIntChangeEdge(desc->m_pin, edge);
#endif
    }
}

BOOL ChkEdge(PIN_ISR_DESCRIPTOR& pinIsr)
{
    BOOL flag = FALSE;
    switch (pinIsr.m_intEdge) {
    case GPIO_INT_EDGE_BOTH:
        flag = TRUE;
        break;
    case GPIO_INT_EDGE_LOW:
    case GPIO_INT_LEVEL_LOW:
        if (pinIsr.m_status == PIN_ISR_DESCRIPTOR::c_Status_AllowLowEdge)
           flag = TRUE;
        break;
    case GPIO_INT_EDGE_HIGH:
    case GPIO_INT_LEVEL_HIGH:
        if (pinIsr.m_status == PIN_ISR_DESCRIPTOR::c_Status_AllowHighEdge)
           flag = TRUE;
        break;
    }
    return flag;
}

void ISR(void)
{
    UINT32 pin;
    NATIVE_PROFILE_HAL_PROCESSOR_GPIO();
    if (m_GPIO_InISR == false) {
        m_GPIO_InISR = true;
        pin = ChkPinChange();
        if (pin != 255) {
            PIN_ISR_DESCRIPTOR &pinIsr = m_PinIsr[m_PinIsr_Ptr[pin]];
            pinIsr.Fire((void *)&pinIsr);
        }
        m_GPIO_InISR = false;
    }
    m_GPIO_Completion.EnqueueDelta(FM4_GPIO_POLLING_INTERVAL);
    return;
}
#endif

void STUB_GPIOISRVector(GPIO_PIN Pin, BOOL PinState, void *Param)
{
}

#ifdef USE_FM4_GPIO_EXT_INT
void ExInt0_7(void *arg)
{
    UINT32 eirr = FM4_EXTI->EIRR;
    UINT32 irq04mon = FM4_INTREQ->IRQ04MON;
    INT32 irq;
    FM4_EXTI->EICL &= ~eirr;        // clear interrupt flag
    irq = GetBitPos(irq04mon, 8);
    if (irq != -1) {
        GPIO_PIN pin = (GPIO_PIN)m_GPIO_IrqToPin[irq];
        if (pin == PPP)
            return;
        PIN_ISR_DESCRIPTOR& pinIsr = m_PinIsr[m_PinIsr_Ptr[pin]];
        if (pinIsr.m_intEdge != GPIO_INT_NONE)
            pinIsr.Fire((void *)&pinIsr);
    }
}

#ifdef MB9BF618T
void ExInt8_31(void *arg)
{
    UINT32 eirr = FM4_EXTI->EIRR;
    UINT32 irq05mon = FM4_INTREQ->IRQ05MON;
    INT32 irq;
    FM4_EXTI->EICL &= ~eirr;        // clear interrupt flag
    irq = GetBitPos(irq05mon, 24);
    if (irq != -1) {
        GPIO_PIN pin = (GPIO_PIN)m_GPIO_IrqToPin[irq+8];
        if (pin == PPP)
            return;
        PIN_ISR_DESCRIPTOR& pinIsr = m_PinIsr[m_PinIsr_Ptr[pin]];
        if (pinIsr.m_intEdge != GPIO_INT_NONE)
            pinIsr.Fire((void *)&pinIsr);
    }
}
#endif
#endif

BOOL EnableInputPin(GPIO_PIN pin, BOOL GlitchFilterEnable, GPIO_INTERRUPT_SERVICE_ROUTINE ISR, void* Param, GPIO_INT_EDGE intEdge, GPIO_RESISTOR resistorState)
{
    UINT32 port = GPIO_PORT(pin);
    UINT32 mask = GPIO_MASK(pin);
    BOOL flag = TRUE;
    GLOBAL_LOCK(irq);
#ifdef FM4_GPIO_INT
    m_PinIsr_Index = PinIsr_AvailableIndex(pin);
    if (m_PinIsr_Index == -1)
        return FALSE;
    m_PinIsr_Ptr[pin] = m_PinIsr_Index;
    PIN_ISR_DESCRIPTOR& pinIsr = m_PinIsr[m_PinIsr_Index];
    pinIsr.m_pin = pin;
    pinIsr.m_intEdge = intEdge;
    pinIsr.m_isr = (ISR != NULL) ? ISR : (GPIO_INTERRUPT_SERVICE_ROUTINE)STUB_GPIOISRVector;
    pinIsr.m_param = Param;
    pinIsr.m_flags = GlitchFilterEnable ? PIN_ISR_DESCRIPTOR::c_Flags_Debounce : 0;
    pinIsr.m_status = 0;
    pinIsr.m_completion.Abort();
    pinIsr.m_completion.Initialize();
    GPIO_PFR(port) &= ~mask;    // GPIO mode
    GPIO_DDR(port) &= ~mask;    // input
    if (resistorState == RESISTOR_DISABLED) {
        GPIO_PCR(port) &= ~mask;
    } else if (resistorState == RESISTOR_PULLUP) {
        GPIO_PCR(port) |= mask;
    }
#ifdef USE_FM4_GPIO_EXT_INT
    if (ExIntAvailable(pin)) {
        // external interrupt
        UINT32 edge = 0;
        switch (intEdge) {
        case GPIO_INT_NONE:
            break;
        case GPIO_INT_EDGE_LOW:
            edge = FM4_INT_EDGE_LOW;
            pinIsr.m_status |= PIN_ISR_DESCRIPTOR::c_Status_AllowLowEdge;
            break;
        case GPIO_INT_LEVEL_LOW:
            edge = FM4_INT_LEVEL_LOW;
            pinIsr.m_status |= PIN_ISR_DESCRIPTOR::c_Status_AllowLowEdge;
            break;
        case GPIO_INT_EDGE_HIGH:
            edge = FM4_INT_EDGE_HIGH;
            pinIsr.m_status |= PIN_ISR_DESCRIPTOR::c_Status_AllowHighEdge;
            break;
        case GPIO_INT_LEVEL_HIGH:
            edge = FM4_INT_LEVEL_HIGH;
            pinIsr.m_status |= PIN_ISR_DESCRIPTOR::c_Status_AllowHighEdge;
            break;
        case GPIO_INT_EDGE_BOTH:
            pinIsr.m_flags |= PIN_ISR_DESCRIPTOR::c_Flags_RequireHighEdge
                    | PIN_ISR_DESCRIPTOR::c_Flags_RequireLowEdge;
            if (CPU_GPIO_GetPinState(pin)) {
                pinIsr.m_status &= ~PIN_ISR_DESCRIPTOR::c_Status_AllowHighEdge;
                pinIsr.m_status |= PIN_ISR_DESCRIPTOR::c_Status_AllowLowEdge;
                edge = FM4_INT_EDGE_LOW;
            } else {
                pinIsr.m_status &= ~PIN_ISR_DESCRIPTOR::c_Status_AllowLowEdge;
                pinIsr.m_status |= PIN_ISR_DESCRIPTOR::c_Status_AllowHighEdge;
                edge = FM4_INT_EDGE_HIGH;
            }
            break;
        default:
            flag;
        }
        ExIntEnable(pin, edge);
    }
    else
#endif
    {
        // polling interrupt
        if (ISR) {
            switch (intEdge) {
            case GPIO_INT_NONE:
                flag = FALSE;
                break;
            case GPIO_INT_EDGE_LOW:
            case GPIO_INT_LEVEL_LOW:
                pinIsr.m_status |= PIN_ISR_DESCRIPTOR::c_Status_AllowLowEdge;
                break;
            case GPIO_INT_EDGE_HIGH:
            case GPIO_INT_LEVEL_HIGH:
                pinIsr.m_status |= PIN_ISR_DESCRIPTOR::c_Status_AllowHighEdge;
                break;
            case GPIO_INT_EDGE_BOTH:
                pinIsr.m_flags |= PIN_ISR_DESCRIPTOR::c_Flags_RequireHighEdge | PIN_ISR_DESCRIPTOR::c_Flags_RequireLowEdge;
                if (CPU_GPIO_GetPinState(pin)) {
                    pinIsr.m_status &= ~PIN_ISR_DESCRIPTOR::c_Status_AllowHighEdge;
                    pinIsr.m_status |=  PIN_ISR_DESCRIPTOR::c_Status_AllowLowEdge;
                } else {
                    pinIsr.m_status &= ~PIN_ISR_DESCRIPTOR::c_Status_AllowLowEdge;
                    pinIsr.m_status |=  PIN_ISR_DESCRIPTOR::c_Status_AllowHighEdge;
                }
                break;
            default:
                flag = FALSE;
            }
        }
        UpdatePinValue(pin);
        EnableInputPolling(pin);
    }
#endif
    return flag;
}

BOOL CPU_GPIO_Initialize()
{
    NATIVE_PROFILE_HAL_PROCESSOR_GPIO();
    GLOBAL_LOCK(irq);
    if (m_GPIO_Driver_Initialized)
        return FALSE;
#ifdef USE_FM4_GPIO_EXT_INT
    CPU_INTC_ActivateInterrupt(EXINT0_7_IRQn, ExInt0_7, 0);
#ifdef MB9BF618T
    CPU_INTC_ActivateInterrupt(EXINT8_31_IRQn, ExInt8_31, 0);
#endif
#endif
    for (UINT32 pin = 0; pin < FM4_GPIO_MAX_PINS; pin++) {
        m_GPIO_Reserved[pin] = FALSE;
        m_PinIsr_Ptr[pin] = 0;
    }
#ifdef FM4_GPIO_INT
    for (UINT32 port = 0; port < FM4_GPIO_MAX_PORTS; port++) {
        m_GPIO_PortReservedMask[port] = 0;
        m_GPIO_PortLastValues[port] = 0;
    }
    m_PinIsr_Index = 1;
    PIN_ISR_DESCRIPTOR *pinIsr = m_PinIsr;
    for (UINT32 i = 0; i < MAX_GPIO_INT; i++) {
        pinIsr->m_pin = PPP;
        pinIsr->m_intEdge = GPIO_INT_NONE;
        pinIsr->m_isr = (GPIO_INTERRUPT_SERVICE_ROUTINE)STUB_GPIOISRVector;
        pinIsr->m_param = NULL;
        pinIsr->m_completion.Initialize();
        pinIsr->m_completion.InitializeForISR(&PIN_ISR_DESCRIPTOR::Fire, pinIsr);
        pinIsr++;
    }
#ifdef USE_FM4_GPIO_EXT_INT
    for (UINT32 i = 0; i < FM4_IRQ_MAX; i++) {
        m_GPIO_IrqToPin[i] = PPP;   // 0xff
    }
    FM4_EXTI->ENIR = 0; // Clear ENable Interrupt request Register
#endif
#endif
    CPU_GPIO_SetDebounce(20);
    m_GPIO_Completion.Initialize();
    m_GPIO_Completion.InitializeForISR((HAL_CALLBACK_FPN)ISR);
    m_GPIO_Completion.EnqueueDelta(FM4_GPIO_POLLING_INTERVAL);
    m_GPIO_Driver_Initialized = TRUE;
    return TRUE;
}

BOOL CPU_GPIO_Uninitialize()
{
    NATIVE_PROFILE_HAL_PROCESSOR_GPIO();
    GLOBAL_LOCK(irq);
#ifdef FM4_GPIO_INT
#ifdef USE_FM4_GPIO_EXT_INT
    CPU_INTC_DeactivateInterrupt(EXINT0_7_IRQn);
#ifdef MB9BF618T
    CPU_INTC_DeactivateInterrupt(EXINT8_31_IRQn);
#endif
    FM4_EXTI->ENIR = 0; // Clear ENable Interrupt request Register
#endif
    m_PinIsr_Index = 1;
    PIN_ISR_DESCRIPTOR* pinIsr = m_PinIsr;
    for (UINT32 i = 0; i < MAX_GPIO_INT; i++) {
        pinIsr->m_completion.Abort();
        pinIsr++;
    }
    m_GPIO_Completion.Abort();
#endif
    m_GPIO_Driver_Initialized = FALSE;
    return true;

}

UINT32 CPU_GPIO_Attributes(GPIO_PIN pin)
{
    NATIVE_PROFILE_HAL_PROCESSOR_GPIO();
    if ((UINT32)pin < FM4_GPIO_MAX_PINS) {
        return DEFAULT_GPIO_ATTRIBUTE;
    }
    return GPIO_ATTRIBUTE_NONE;
}

void CPU_GPIO_DisablePin(GPIO_PIN pin, GPIO_RESISTOR ResistorState, UINT32 Direction, GPIO_ALT_MODE AltFunction)
{
    NATIVE_PROFILE_HAL_PROCESSOR_GPIO();
    GLOBAL_LOCK(irq);
    GPIO_PFR(GPIO_PORT(pin)) |= GPIO_MASK(pin);    // Peripheral mode
#ifdef FM4_GPIO_INT
    m_PinIsr_Ptr[pin] = 0;
#ifdef USE_FM4_GPIO_EXT_INT
    if (ExIntAvailable(pin))
        ExIntDisable(pin);
    else
#endif
        DisableInputPolling(pin);
#endif
}

void CPU_GPIO_EnableOutputPin(GPIO_PIN pin, BOOL initialState)
{
    NATIVE_PROFILE_HAL_PROCESSOR_GPIO();
    CPU_GPIO_SetPinState(pin, initialState);
#ifdef FM4_GPIO_INT
    m_PinIsr_Ptr[pin] = 0;
#ifdef USE_FM4_GPIO_EXT_INT
    if (ExIntAvailable(pin))
        ExIntDisable(pin);
    else
#endif
        DisableInputPolling(pin);
#endif
}

BOOL CPU_GPIO_EnableInputPin(GPIO_PIN Pin, BOOL GlitchFilterEnable, GPIO_INTERRUPT_SERVICE_ROUTINE ISR, GPIO_INT_EDGE IntEdge, GPIO_RESISTOR ResistorState)
{
    NATIVE_PROFILE_HAL_PROCESSOR_GPIO();
    return CPU_GPIO_EnableInputPin2(Pin, GlitchFilterEnable, ISR, 0, IntEdge, ResistorState);
}

BOOL CPU_GPIO_EnableInputPin2(GPIO_PIN Pin, BOOL GlitchFilterEnable, GPIO_INTERRUPT_SERVICE_ROUTINE ISR, void* ISR_Param, GPIO_INT_EDGE IntEdge, GPIO_RESISTOR ResistorState)
{
    NATIVE_PROFILE_HAL_PROCESSOR_GPIO();
    return EnableInputPin(Pin, GlitchFilterEnable, ISR, ISR_Param, IntEdge, ResistorState);
}

BOOL CPU_GPIO_GetPinState(GPIO_PIN pin)
{
    NATIVE_PROFILE_HAL_PROCESSOR_GPIO();
    UINT32 port = GPIO_PORT(pin);
    UINT32 mask = GPIO_MASK(pin);
    GLOBAL_LOCK(irq);
    GPIO_PFR(port) &= ~mask;        // GPIO mode
    GPIO_DDR(port) &= ~mask;        // input
    return GPIO_PDIR(port) & mask;
}

void CPU_GPIO_SetPinState(GPIO_PIN pin, BOOL pinState)
{
    NATIVE_PROFILE_HAL_PROCESSOR_GPIO();
    UINT32 port = GPIO_PORT(pin);
    UINT32 mask = GPIO_MASK(pin);
    GLOBAL_LOCK(irq);
    GPIO_PFR(port) &= ~mask;        // GPIO mode
    GPIO_DDR(port) |= mask;         // output
    if (pinState)
        GPIO_PDOR(port) |= mask;
    else
        GPIO_PDOR(port) &= ~mask;
}

INT32 CPU_GPIO_GetPinCount()
{
    NATIVE_PROFILE_HAL_PROCESSOR_GPIO();
    return FM4_GPIO_MAX_PINS;
}

void CPU_GPIO_GetPinsMap(UINT8* pins, size_t size)
{
    NATIVE_PROFILE_HAL_PROCESSOR_GPIO();
    GPIO_PIN pin;
    for (pin = (GPIO_PIN)0; pin < (GPIO_PIN)FM4_GPIO_MAX_PINS; pin++) {
        if (size-- == 0)
            break;
        *pins++ = (UINT8)DEFAULT_GPIO_ATTRIBUTE;
    }
}

UINT8 CPU_GPIO_GetSupportedResistorModes(GPIO_PIN pin)
{
    NATIVE_PROFILE_HAL_PROCESSOR_GPIO();
    return (1 << RESISTOR_DISABLED) | (1 << RESISTOR_PULLUP);

}

UINT8 CPU_GPIO_GetSupportedInterruptModes(GPIO_PIN pin)
{
    NATIVE_PROFILE_HAL_PROCESSOR_GPIO();
    return (1 << GPIO_INT_EDGE_LOW) |
           (1 << GPIO_INT_EDGE_HIGH ) |
           (1 << GPIO_INT_EDGE_BOTH);
}

BOOL CPU_GPIO_PinIsBusy(GPIO_PIN pin)
{
    NATIVE_PROFILE_HAL_PROCESSOR_GPIO();
    return m_GPIO_Reserved[pin];
}

BOOL CPU_GPIO_ReservePin(GPIO_PIN pin, BOOL fReserve)
{
    NATIVE_PROFILE_HAL_PROCESSOR_GPIO();
    m_GPIO_Reserved[pin] = fReserve;
    return true;
}

UINT32 CPU_GPIO_GetDebounce()
{
    NATIVE_PROFILE_HAL_PROCESSOR_GPIO();
    return CPU_TicksToTime(m_DebounceTicks) / 10000;
}

BOOL CPU_GPIO_SetDebounce(INT64 debounceTimeMilliseconds)
{
    NATIVE_PROFILE_HAL_PROCESSOR_GPIO();
    if (debounceTimeMilliseconds < MIN_DEBOUNCETIMEMS || MAX_DEBOUNCETIMEMS < debounceTimeMilliseconds)
        return false;
    m_DebounceTicks = CPU_MillisecondsToTicks((UINT32)debounceTimeMilliseconds);
    return true;
}
